﻿using System;
using System.IO;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Text;
using System.Web;
using System.Text.RegularExpressions;
using System.Collections;
using System.Configuration;
using System.Reflection;
using System.Data;
using System.Linq;
using System.Net;
using System.Web.Script.Serialization;
using System.Drawing;
using System.Drawing.Imaging;

namespace QBS.Tools
{
    public static class Utils
    {
        public static string Md5Token(string val)
        {
            if (!val.IsEmpty())
            {
                System.Security.Cryptography.MD5CryptoServiceProvider md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
                byte[] bs = System.Text.Encoding.UTF8.GetBytes(val);
                bs = md5.ComputeHash(bs);
                System.Text.StringBuilder s = new System.Text.StringBuilder();
                for (int i = 4; i <= 11; i++)
                {
                    s.Append(bs[i].ToString("x2"));
                }
                return s.ToString().ToUpper();
            }
            return "";
        }
        ///// <summary>  
        ///// 生成二维码  
        ///// </summary>  
        ///// <param name="content">内容</param>
        ///// <param name="moduleSize">二维码的大小</param>
        ///// <returns>输出流</returns>  
        //public static MemoryStream QRCode(string content, int moduleSize = 9, string iconPath = "")
        //{
        //    //ErrorCorrectionLevel 误差校正水平
        //    //QuietZoneModules     空白区域

        //    var encoder = new QrEncoder(ErrorCorrectionLevel.M);
        //    QrCode qrCode = encoder.Encode(content);
        //    GraphicsRenderer render = new GraphicsRenderer(new FixedModuleSize(moduleSize, QuietZoneModules.Two), Brushes.Black, Brushes.White);

        //    MemoryStream memoryStream = new MemoryStream();
        //    if (File.Exists(iconPath))
        //    {
        //        DrawingSize dSize = render.SizeCalculator.GetSize(qrCode.Matrix.Width);
        //        Bitmap map = new Bitmap(dSize.CodeWidth, dSize.CodeWidth);
        //        Graphics g = Graphics.FromImage(map);
        //        render.Draw(g, qrCode.Matrix);

        //        //追加Logo图片 ,注意控制Logo图片大小和二维码大小的比例
        //        //PS:追加的图片过大超过二维码的容错率会导致信息丢失,无法被识别
        //        Image img = Image.FromFile(iconPath);

        //        Point imgPoint = new Point((map.Width - img.Width) / 2, (map.Height - img.Height) / 2);
        //        g.DrawImage(img, imgPoint.X, imgPoint.Y, img.Width, img.Height);
        //        map.Save(memoryStream, ImageFormat.Jpeg);
        //    }
        //    else
        //    {
        //        render.WriteToStream(qrCode.Matrix, ImageFormat.Jpeg, memoryStream);
        //    }
        //    //byte[] buf = new byte[memoryStream.Length];
        //    //memoryStream.Read(buf, 0, (int)memoryStream.Length);
        //    //return buf;
        //    return memoryStream;
        //}
        /// <summary>
        /// 合并图片
        /// </summary>
        /// <param name="stm">源图片</param>
        /// <param name="old">目标图片</param>
        /// <returns></returns>
        public static byte[] MergePic(Stream stm, byte[] old)
        {
            byte[] buf;
            if (old == null)
            {
                buf = new byte[stm.Length];
                stm.Read(buf, 0, buf.Length);
            }
            else
            {
                System.Drawing.Image newpic = System.Drawing.Image.FromStream(stm);
                MemoryStream mem = new MemoryStream();
                mem.SetLength(old.Length);
                mem.Write(old, 0, old.Length);
                System.Drawing.Image oldpic = System.Drawing.Image.FromStream(mem);

                int w_new = newpic.Width;
                int h_new = newpic.Height;

                int w_old = oldpic.Width;
                int h_old = oldpic.Height;

                //新建一个bmp图片
                System.Drawing.Image bitmap = new System.Drawing.Bitmap(w_new + w_old, h_old);
                //新建一个画板
                Graphics g = System.Drawing.Graphics.FromImage(bitmap);
                //设置高质量插值法
                g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;
                //设置高质量,低速度呈现平滑程度
                g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                //清空画布并以透明背景色填充
                g.Clear(Color.Transparent);
                //在指定位置并且按指定大小绘制原图片的指定部分
                g.DrawImage(oldpic, new Rectangle(0, 0, w_old, h_old),
                    new Rectangle(0, 0, w_old, h_old),
                    GraphicsUnit.Pixel);
                //在指定位置并且按指定大小绘制原图片的指定部分
                g.DrawImage(newpic, new Rectangle(w_old, 0, w_new, h_old),
                    new Rectangle(0, 0, w_new, h_new),
                    GraphicsUnit.Pixel);
                MemoryStream ret = new MemoryStream();
                try
                {
                    newpic.Dispose();
                    oldpic.Dispose();
                    //FileInfo file = new FileInfo(originalImagePath);
                    //file.Delete();
                    //以jpg格式保存缩略图
                    //bitmap.Save("d:\\t.jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
                    bitmap.Save(ret, System.Drawing.Imaging.ImageFormat.Jpeg);

                    buf = new byte[ret.Length];
                    ret.Position = 0;
                    ret.Read(buf, 0, Convert.ToInt32(ret.Length));
                }
                catch (System.Exception e)
                {
                    throw e;
                }
                finally
                {
                    bitmap.Dispose();
                    g.Dispose();
                    mem.Dispose();
                    ret.Dispose();
                }

            }
            return buf;
        }
        /// <summary>
        /// 生成缩略图
        /// </summary>
        /// <param name="originalImagePath">源图路径（物理路径）</param>
        /// <param name="thumbnailPath">缩略图路径（物理路径）</param>
        /// <param name="width">缩略图宽度</param>
        /// <param name="height">缩略图高度</param>
        /// <param name="mode">生成缩略图的方式</param>    
        public static void MakeThumbnail(string originalImagePath, string thumbnailPath, int width, int height, string mode = "HW")
        {
            System.Drawing.Image originalImage = System.Drawing.Image.FromFile(originalImagePath);

            int towidth = width;
            int toheight = height;

            int x = 0;
            int y = 0;
            int ow = originalImage.Width;
            int oh = originalImage.Height;

            switch (mode)
            {
                case "HW"://指定高宽缩放（可能变形）                
                    break;
                case "W"://指定宽，高按比例                    
                    toheight = originalImage.Height * width / originalImage.Width;
                    break;
                case "H"://指定高，宽按比例
                    towidth = originalImage.Width * height / originalImage.Height;
                    break;
                case "Cut"://指定高宽裁减（不变形）                
                    if ((double)originalImage.Width / (double)originalImage.Height > (double)towidth / (double)toheight)
                    {
                        oh = originalImage.Height;
                        ow = originalImage.Height * towidth / toheight;
                        y = 0;
                        x = (originalImage.Width - ow) / 2;
                    }
                    else
                    {
                        ow = originalImage.Width;
                        oh = originalImage.Width * height / towidth;
                        x = 0;
                        y = (originalImage.Height - oh) / 2;
                    }
                    break;
                default:
                    break;
            }

            //新建一个bmp图片
            System.Drawing.Image bitmap = new System.Drawing.Bitmap(towidth, toheight);
            //新建一个画板
            Graphics g = System.Drawing.Graphics.FromImage(bitmap);
            //设置高质量插值法
            g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;
            //设置高质量,低速度呈现平滑程度
            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
            //清空画布并以透明背景色填充
            g.Clear(Color.Transparent);
            //在指定位置并且按指定大小绘制原图片的指定部分
            g.DrawImage(originalImage, new Rectangle(0, 0, towidth, toheight),
                new Rectangle(x, y, ow, oh),
                GraphicsUnit.Pixel);
            try
            {
                originalImage.Dispose();
                //FileInfo file = new FileInfo(originalImagePath);
                //file.Delete();
                //以jpg格式保存缩略图
                bitmap.Save(thumbnailPath, System.Drawing.Imaging.ImageFormat.Jpeg);
            }
            catch (System.Exception e)
            {
                throw e;
            }
            finally
            {
                originalImage.Dispose();
                bitmap.Dispose();
                g.Dispose();
            }
        }
        public static string MD5File(string path)
        {
            try
            {
                if (File.Exists(path))
                {
                    FileStream file = new FileStream(path, FileMode.Open);
                    System.Security.Cryptography.MD5 md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
                    byte[] bs = md5.ComputeHash(file);
                    file.Close();

                    StringBuilder sb = new StringBuilder();
                    foreach (byte b in bs)
                    {
                        sb.Append(b.ToString("x2"));
                    }
                    return sb.ToString();
                }
            }
            catch (Exception)
            {
            }
            return "";
        }
        public static string MD5Encrypt(string val)
        {
            if (!val.IsEmpty())
            {
                System.Security.Cryptography.MD5CryptoServiceProvider md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
                byte[] bs = System.Text.Encoding.UTF8.GetBytes(val);
                bs = md5.ComputeHash(bs);
                System.Text.StringBuilder s = new System.Text.StringBuilder();
                foreach (byte b in bs)
                {
                    s.Append(b.ToString("x2"));
                }
                return s.ToString();
            }
            return "";
            //return System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(val, "MD5");
        }

        public static string getWeek(DateTime day)
        {
            switch ((int)day.DayOfWeek)
            {
                case 1: return "周一";
                case 2: return "周二";
                case 3: return "周三";
                case 4: return "周四";
                case 5: return "周五";
                case 6: return "周六";
                default: return "周日";
            }
        }

        public static bool IsTel<T>(this T tel)
        {
            //string pattern = @"^\d{6,15}$";
            string pattern = @"^(\d{5,13})|(\d{2,4}-\d{4,9})$";
            if (tel.IsEmpty())
                return false;
            return Regex.IsMatch(tel.ToString().Trim(), pattern);
        }
        //18655650521
        public static bool IsPhone<T>(this T phone)
        {
            //string pattern = @"^\d{6,15}$";
            string pattern = @"^1[3456789][0-9]\d{8}$";
            if (phone.IsEmpty())
                return false;
            return Regex.IsMatch(phone.ToString().Trim(), pattern);
        }
        public static bool IsChinese<T>(this T hz)
        {
            char[] c = hz.ToString().ToCharArray();

            for (int i = 0; i < c.Length; i++)
            {
                if (c[i] < 0x4e00 || c[i] > 0x9fbb)
                    return false;
            }
            return true;
        }
        public static string Cut(object obj, int length)
        {
            string tmp = obj.ToString();
            return tmp.Length > length ? string.Format("<span title=\"{0}\">{1}...</span>", tmp, tmp.Substring(0, length - 1)) : tmp;
        }

        public static T ToEntity<T>(string val)
        {
            JavaScriptSerializer jss = new JavaScriptSerializer();
            return jss.Deserialize<T>(val);
        }

        public static bool IsNull<T>(this T val)
        {
            return val == null || val is DBNull;
        }
        public static bool HasVal<T>(this T val)
        {
            return val != null && !String.IsNullOrEmpty(val.ToString().Trim());
        }
        public static bool IsEmpty<T>(this T val)
        {
            return val == null || String.IsNullOrEmpty(val.ToString().Trim());
        }

        public static object GetValue(this Dictionary<string, object> dic, string key)
        {
            if (dic.Keys.Contains(key))
                return dic[key];
            return string.Empty;
        }
        private static Dictionary<string, string> NvcToDic(NameValueCollection nvc)
        {
            Dictionary<string, string> dic = new Dictionary<string, string>();
            foreach (string key in nvc.Keys)
            {
                if (!key.IsEmpty())
                    dic.Add(key, nvc[key]);
            }
            return dic;
        }

        /// <summary>
        /// 序列化为JSON格式
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="val"></param>
        /// <returns></returns>
        public static string enJson<T>(this T val)
        {
            if (val.IsEmpty())
                return "";
            JavaScriptSerializer jss = new JavaScriptSerializer();
            if (val.GetType().ToString().Contains("DataTable"))
            {
                return jss.Serialize(DataTableToDictionary(val as DataTable));
            }
            if (val.GetType().ToString().Contains("DataRow"))
            {
                return jss.Serialize(DataRowToDictionary(val as DataRow));
            }
            var nv = val as NameValueCollection;
            if (nv != null)
                return jss.Serialize(NvcToDic(nv));
            return jss.Serialize(val);
        }

        /// <summary>
        /// 反序列化为对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="val"></param>
        /// <returns></returns>
        public static T deJson<T>(this string val)
        {
            if (!val.IsEmpty())
            {
                JavaScriptSerializer jss = new JavaScriptSerializer();
                return jss.Deserialize<T>(val);
            }
            return default(T);
        }
        private static List<Dictionary<string, object>> DataTableToDictionary(DataTable table)
        {
            List<Dictionary<string, object>> items = new List<Dictionary<string, object>>();
            foreach (DataRow dr in table.Rows)
            {
                Dictionary<string, object> item = new Dictionary<string, object>();
                foreach (DataColumn col in table.Columns)
                {
                    item.Add(col.ColumnName, dr[col.ColumnName]);
                }
                items.Add(item);
            }
            return items;
        }
        private static Dictionary<string, object> DataRowToDictionary(DataRow dr)
        {
            List<Dictionary<string, object>> items = new List<Dictionary<string, object>>();

            Dictionary<string, object> item = new Dictionary<string, object>();
            foreach (DataColumn col in dr.Table.Columns)
            {
                item.Add(col.ColumnName, dr[col.ColumnName]);
            }
            return item;
        }

        public static bool IsOnline(string strUserID, Hashtable h)
        {
            if (strUserID == null)
                return false;

            //继续判断是否该用户已经登陆 
            if (h == null)
                return false;

            //判断哈希表中是否有该用户 
            IDictionaryEnumerator e1 = h.GetEnumerator();
            bool flag = false;
            while (e1.MoveNext())
            {
                if (e1.Value.ToString().CompareTo(strUserID) == 0)
                {
                    flag = true;
                    break;
                }
            }
            return flag;
        }

        public static bool IsQQ<T>(this T QQ)
        {
            return Regex.IsMatch(QQ.ToString(), "^[1-9][0-9]{4,10}$");
        }

        public static bool IsEmail<T>(this T Email)
        {
            return Regex.IsMatch(Email.ToString(), @"\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*");
        }

        public static string ToSafe<T>(this T str)
        {
            if (str.IsNull())
                return "";
            string tmp = str.ToString();
            if (!tmp.IsEmpty())
            {
                tmp = tmp.Replace("'", "''");
            }
            return tmp;
        }
        public static string ToCut<T>(this T o, int len)
        {
            string tmp = o.ToString();
            return tmp.Length > len ? tmp.Substring(0, len) + "..." : tmp;
        }
        public static DateTime ToDate<T>(this T o, DateTime? dt = null)
        {
            try
            {
                if (o.GetType().Name == "Int64")
                    return new DateTime(o.ToLong());
                return DateTime.Parse(o.ToString());
            }
            catch
            {
                if (dt.HasValue)
                    return dt.Value;
                return DateTime.Parse("1987-04-18"); //DateTime.MinValue;
            }
        }

        public static bool IsTime<T>(this T o)
        {
            string tm = o.ToString();
            if (tm.IsEmpty())
                return false;
            string ret = string.Empty;
            string[] tmp = tm.Split(':');
            if (tmp.Count() > 1)
            {
                string t = tmp[0];
                if (t.Substring(0, 1) == "0")
                    t = t.Substring(1, 1);
                if (t.ToInt() < 0 || t.ToInt() > 23)
                    return false;
                t = tmp[1];
                if (t.Substring(0, 1) == "0")
                    t = t.Substring(1, 1);
                if (t.ToInt() < 0 || t.ToInt() > 59)
                    return false;
            }
            return true;
        }
        public static bool IsJSON<T>(this T o)
        {
            string tm = o.ToString();
            if (tm.IsEmpty())
                return false;

            return tm.Substring(0, 1) == "{" && tm.Substring(tm.Length - 1, 1) == "}";
        }
        public static string ToStr<T>(this T o)
        {
            return o == null ? "" : o.ToString();
        }

        public static int ToInt<T>(this T o)
        {
            try
            {
                return int.Parse(o.ToString());
            }
            catch
            {
                return 0;
            }
        }
        public static decimal ToMoney<T>(this T o)
        {
            try
            {
                var c = decimal.Parse(o.ToString());
                return Math.Round(c, 2);
            }
            catch
            {
                return 0;
            }
        }
        public static decimal ToDecimal<T>(this T o)
        {
            try
            {
                return decimal.Parse(o.ToString());
            }
            catch
            {
                return 0;
            }
        }

        public static double ToDouble<T>(this T o)
        {
            try
            {
                return double.Parse(o.ToString());
            }
            catch
            {
                return 0;
            }
        }

        public static bool ToBool<T>(this T o)
        {
            try
            {
                return bool.Parse(o.ToString());
            }
            catch
            {
                return false;
            }
        }

        public static long ToLong<T>(this T o)
        {
            try
            {
                return long.Parse(o.ToString());
            }
            catch
            {
                return 0;
            }
        }

        public static string Select(this string o, string subWhere, params object[] arrVal)
        {
            if (!subWhere.IsEmpty())
            {
                for (int i = 0; i < arrVal.Length; i++)
                {
                    if (!arrVal[i].IsNull() && arrVal[i].GetType().Name == "String")
                    {
                        string strTmp = "";
                        if (!arrVal[i].IsEmpty())
                            strTmp = arrVal[i].ToString();
                        //检测不安全参数,防止SQL注入
                        strTmp = strTmp.ToSafe();
                        //检测如果参数为 x in (xxx) 去除xxx最后一个逗号
                        if (subWhere.ToLower().Contains(" in "))
                        {
                            if (strTmp.IsEmpty())
                                strTmp = "0";
                            if (strTmp.EndsWith(","))
                                strTmp = strTmp.Substring(0, strTmp.Length - 1);
                        }
                        //将值返回来
                        arrVal[i] = strTmp;
                    }
                }
                subWhere = string.Format(subWhere, arrVal);
            }

            if (!o.IsEmpty())
            {
                if (!subWhere.IsEmpty())
                {
                    return string.Format("{0} and ({1})", o, subWhere);
                }
                return o;
            }
            else
            {
                if (!subWhere.IsEmpty())
                {
                    string tmp = subWhere.Trim();
                    if (tmp.StartsWith("or "))
                        tmp = tmp.Remove(0, 3);
                    if (tmp.StartsWith("and "))
                        tmp = tmp.Remove(0, 4);
                    return " (" + tmp + ") ";
                }
                return "";
            }
        }
        // strWhere   =   " intID=3  " //   and (dtDate>'2011' or dtDate<2013)  "
        public static string Select(this string o, string subWhere)
        {
            if (!o.IsEmpty())
            {
                if (!subWhere.IsEmpty())
                {
                    return string.Format("{0} and ({1})", o, subWhere);
                }
                return o;
            }
            else
            {
                if (!subWhere.IsEmpty())
                {
                    string tmp = subWhere.Trim();
                    if (tmp.StartsWith("or "))
                        tmp = tmp.Remove(0, 3);
                    if (tmp.StartsWith("and "))
                        tmp = tmp.Remove(0, 4);
                    return " (" + tmp + ") ";
                }
                return "";
            }
        }

        public static void CopyObject<T>(this T tSource, T tDestination) where T : class
        {
            //获得所有property的信息
            PropertyInfo[] properties = tSource.GetType().GetProperties();
            foreach (PropertyInfo p in properties)
            {
                //PropertyType = {Name = "EntityState" FullName = "System.Data.EntityState"}
                if (p.Name == "EntityState" || p.Name == "EntityKey" || p.Name == "intID") continue;
                p.SetValue(tDestination, p.GetValue(tSource, null), null);//设置tDestination的属性值              
            }
        }
        public static string GetFilePath(string file)
        {
            return HttpContext.Current == null ? HttpRuntime.AppDomainAppPath + file : HttpContext.Current.Server.MapPath(file);
        }

        /// <summary>
        /// 记录错误日志
        /// </summary>
        /// <param name="msg"></param>
        public static void WrLog(string sort, string msg)
        {
            if ((File.Exists(GetFilePath("/debug.txt")) && !sort.StartsWith("SQL")) || (File.Exists(GetFilePath("/sql.txt")) && sort.StartsWith("SQL")))
            {
                StreamWriter sw = null;
                DateTime date = DateTime.Now;
                string FileName = string.Empty;
                try
                {
                    FileName = GetFilePath("/Logs/INFO-" + date.ToString("yyMMdd") + ".txt");
                    if (sort.StartsWith("SQL"))
                        FileName = GetFilePath("/Logs/SQL-" + date.ToString("yyMMdd") + ".txt");
                    if (sort.StartsWith("PAY"))
                        FileName = GetFilePath("/Logs/PAY-" + date.ToString("yyMMdd") + ".txt");
                    #region 检测日志目录是否存在
                    string forderPathStr = null;
                    if (HttpContext.Current == null)
                    {
                        forderPathStr = HttpRuntime.AppDomainAppPath + "/Logs";
                    }
                    else
                    {
                        forderPathStr = HttpContext.Current.Server.MapPath("~/Logs");
                    }
                    if (!Directory.Exists(forderPathStr))
                    {
                        Directory.CreateDirectory(forderPathStr);
                    }

                    if (!File.Exists(FileName))
                    {
                        sw = File.CreateText(FileName);//不存在该文件，就创建并添加内容
                    }
                    else
                    {
                        sw = File.AppendText(FileName);//日志文件已经存在，则向该文件追加内容
                    }
                    #endregion
                    sw.WriteLine(string.Format("[{0}]Url:{2}", date.ToString("yyyy-MM-dd HH:mm:ss"), sort, (HttpContext.Current != null ? HttpContext.Current.Request.Url.ToString() : "")));
                    sw.WriteLine(string.Format("[{0}]{1}:{2}\n\n", date.ToString("yyyy-MM-dd HH:mm:ss"), sort, msg));
                    sw.Flush();
                }
                catch { }
                finally
                {
                    if (sw != null)
                        sw.Close();
                }
            }
        }

        public static string deParam(Stream stream)
        {
            string ret = string.Empty;

            byte[] szBin = new byte[stream.Length];
            int size = (int)stream.Length;
            stream.Read(szBin, 0, size); //Encoding.Default.GetBytes(stream);  //Encoding.Default.GetBytes(Server.UrlDecode(param));
            for (int i = 0; i < szBin.Length; i++)
            {
                string tmp = Convert.ToString(int.Parse(szBin[i].ToString()), 16);
                ret += tmp.Length == 1 ? "0" + tmp : tmp;
            }
            return ret.ToUpper();
        }

        public static byte[] enParam(string param)
        {
            if (!String.IsNullOrEmpty(param))
            {
                int len = param.Length;
                byte[] szBin = new byte[len / 2];
                for (int i = 0; i < len; i += 2)
                {
                    szBin[i / 2] = (byte)int.Parse(param.Substring(i, 2), System.Globalization.NumberStyles.HexNumber);
                }
                return szBin;
            }
            return null;
        }
        private static WebClient _client = new WebClient();
        public static string Post(string url, string data = "", string userAgent = "")
        {
            try
            {
                WrLog("soap", url + "|" + data);
                string ret = string.Empty;
                if (data.IsEmpty())
                {
                    byte[] by = _client.DownloadData(url);
                    ret = Encoding.UTF8.GetString(by);
                }
                else
                {
                    byte[] bytes = Encoding.Default.GetBytes(data);
                    _client.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
                    _client.Headers.Add("ContentLength", bytes.Length.ToString());
                    if (userAgent != "")
                        _client.Headers.Add("User-Agent", userAgent);
                    bytes = _client.UploadData(url, "POST", bytes);
                    ret = Encoding.UTF8.GetString(bytes);
                }
                WrLog("soap ret", ret);
                return ret;
            }
            catch (Exception ex)
            {
                Utils.WrLog("连接接口服务器", ex.Message);
            }
            return "";
        }
    }
}